//////////////////////////////////////////////////////////
//
//	File: board.h
//	Version 1.0
//	Authors: Adam Couch, Victoria Sater
//  Description: Holds methods for Board class
//
//////////////////////////////////////////////////////////

#ifndef BOARD_H
#define BOARD_H

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "hole.h"

using namespace std;

class Board {
public:
	
	vector<Hole> holes;		// vector of current state of holes
	int computerScore;		// score	
	int playerScore;		// player score

	// default constructor
	Board() {
		srand ( (size_t)time(NULL) );	// random seed
		// initialize board
		for (int i = 0; i < 14; ++i)
		{
			Hole hole;
			if (i== 0 || i==7)
				hole.setNum(0);
			else hole.setNum(4);
			holes.push_back(hole);
		}
	}
	// constructor taking holes as parameters
	Board(vector<Hole> newHoles) 
	{
		srand ( (size_t)time(NULL) );	// random seed
		// initialize board
		setHoles(newHoles);
	}

	// getters/setters
	vector<Hole> getHoles() { return holes; }
	int getComputerScore() { return computerScore; }
	int getPlayerScore() { return playerScore; }

	void setHoles(vector<Hole> newHoles) { holes = newHoles; }
	void setComputerScore(int newScore) { computerScore = newScore; }
	void setPlayerScore(int newScore) { playerScore = newScore; }

	// makeMove
	// player: computer means 0, person means 1
	bool makeMove(int player, int index) {
		int numPebbles = holes[index].getNum();
		int loc = 0;
		holes[index].setNum(0);
		for (int i = 1; i <= numPebbles; ++i)
		{
			loc = index + i;
			while (loc > 13)
				loc -= 14;
			if ((loc == 0 && player == 1) || (loc == 7 && player == 0))
			{
				// skip space
				numPebbles++;
			}
			else
				holes[loc].addOne();
		}
		// check if player "stole" opponents pebbles
		if ( holes[loc].getNum() == 1 && loc != 0 && loc != 7 && holes[holes[loc].getOppositeHole(loc)].getNum() > 0)
		{
			if ( player == 1 && loc < 7)
			{
				holes[7].addSome( holes.at( holes[loc].getOppositeHole(loc) ).getNum() + 1 );
				holes.at( holes[loc].getOppositeHole(loc) ).setNum(0);
				holes[loc].setNum(0);
			}
			else if ( player == 0 && loc > 7)
			{
				holes[0].addSome( holes.at( holes[loc].getOppositeHole(loc) ).getNum() + 1 );
				holes.at( holes[loc].getOppositeHole(loc) ).setNum(0);
				holes[loc].setNum(0);
			}
		}
		// check if player will move again
		if ( (loc == 0 && player == 0) || (loc == 7 && player == 1) )
			return true;
		return false;
	}

	int randomMove() { return (rand() % 6 + 8); }

    // calculate simple H - adding points only
	void calculateSimpleH() {
		for (int i = 8; i <= 13; ++i)
		{
			holes[i].setH(0);
			int numPebbles = holes[i].getNum();
			int newLoc = numPebbles + i;
			int rounds = 0;
			while (newLoc > 13) 
			{
				holes[i].setH(holes[i].getH() + 1);
				newLoc -= 14;
				rounds++;
			}
			if (newLoc > 7 && holes[newLoc].getNum() + rounds == 0 && holes[holes[newLoc].getOppositeHole(newLoc)].getNum() + rounds > 0)
				holes[i].setH(holes[i].getH() + holes[holes[newLoc].getOppositeHole(newLoc)].getNum() + rounds + 1);
		}
	}

	void calculateComplexH() {
		for (int i = 1; i <= 13; ++i)
		{
			holes[i].setH(0);
			int numPebbles = holes[i].getNum();
			int newLoc = numPebbles + i;
			int rounds = 0;
			while (newLoc > 13) 
			{
				holes[i].setH(holes[i].getH() + 1);
				newLoc -= 14;
				rounds++;
			}
			if (newLoc == 0 || newLoc == 7)
				holes[i].setH(holes[i].getH() + i); // add i instead of 1 so that the ones closer to the hole are chosen first
			else if ( newLoc != 0 && newLoc != 7 && holes[newLoc].getNum() + rounds == 0 && (holes[holes[newLoc].getOppositeHole(newLoc)].getNum() + rounds > 0) )
				holes[i].setH(holes[i].getH() + holes[holes[newLoc].getOppositeHole(newLoc)].getNum() + rounds + i);
		}
	}

    // determine if game is over, add any remaining pebbles to appropriate holes
    bool endGame() {
        bool gameOver = false;
		int count = 0;
        if ((holes[13].getNum() == 0 && holes[12].getNum() == 0 && holes[11].getNum() == 0 && holes[10].getNum() == 0 && holes[9].getNum() == 0 && holes[8].getNum() == 0) ||
                (holes[1].getNum() == 0 && holes[2].getNum() == 0 && holes[3].getNum() == 0 && holes[4].getNum() == 0 && holes[5].getNum() == 0 && holes[6].getNum() == 0))
		{
			for (int i=1; i<7; i++)
			{
				count += holes[i].getNum();
				holes[i].setNum(0);
			}
			holes[7].addSome(count);
			count = 0;
			for (int i=8; i<=13; i++)
			{
				count += holes[i].getNum();
				holes[i].setNum(0);
			}
			holes[0].addSome(count);
			gameOver = true;
		}
        return gameOver;        
    }

	// printBoard
	void printBoard() {
		cout << "=========================================\n";
		cout << "|    | "; for (int i=13; i>=8; i--) printHole(i); cout << "   |\n";
		cout << "|    |=============================|    |\n";
		cout << "| "; printHole(0); cout << "                            | "; printHole(7); cout << "\n";
		cout << "|    |=============================|    |\n";
		cout << "|    | "; for (int i=1; i<=6; i++) printHole(i); cout << "   |\n";
		cout << "=========================================\n";	
	}
	// printDefaultBoard ( to easily see the numbering of the holes )
	void printDefaultBoard() {
		cout << "=========================================\n";
		cout << "|    | 13 | 12 | 11 | 10 |  9 |  8 |    |\n";
		cout << "|    |=============================|    |\n";
		cout << "|  0 |                             |  7 |\n";
		cout << "|    |=============================|    |\n";
		cout << "|    |  1 |  2 |  3 |  4 |  5 |  6 |    |\n";
		cout << "=========================================\n\n";	
	}
	// print the number of pebbles in a hole
	void printHole(int index)
	{
		if ( holes[index].getNum() < 10 )
			cout << " ";
		cout << holes[index].getNum() << " | ";
	}

	// determine outcome of the game at current state for player (0=comp, 1=human)
	int evaluateGame(vector<Hole> theHoles, int player)
	{
		if (endGame())
		{
			if (player==0) return (theHoles[0].getNum() - theHoles[7].getNum() );
			else return (theHoles[7].getNum() - theHoles[0].getNum() );
		}
		calculateComplexH();
		return getValue(player);
	}

	// return possible moves for player (0=comp, 1=human)
	vector<int> possibleMoves(int player)
	{
		vector<int> temp;
		int lowBound = 1;
		int highBound = 6;
		if (player == 0)	// change bounds for computer
		{
			lowBound = 8;
			highBound = 13;
		}
		for (int i=lowBound; i<= highBound; i++)
			if ( holes[i].getNum() > 0 ) temp.push_back(i);
		return temp;
	}

	int getValue(int player)
	{
		int temp = 0;
		int player0 = 0;
		int player1 = 0;

		for (int i=8; i<= 13; i++)
			player0+=holes[i].getNum();	
		for (int i=1; i<= 6; i++)
			player1+=holes[i].getNum();	

		if (player == 0)
			temp = (holes[0].getNum() - holes[7].getNum() )*10 + player0 - player1;
		else temp = (holes[7].getNum() - holes[0].getNum() )*10 + player1 - player0;

		return temp;
	}  
	
};

#endif
